/*! \file avrlibdefs.h \brief AVRlib global defines and macros. */
//*****************************************************************************
//
// File Name	: 'avrlibdefs.h'
// Title		: AVRlib global defines and macros include file
// Author		: Pascal Stang
// Created		: 7/12/2001
// Revised		: 9/30/2002
// Version		: 1.1
// Target MCU	: Atmel AVR series
// Editor Tabs	: 4
//
//	Description : This include file is designed to contain items useful to all
//					code files and projects, regardless of specific implementation.
//
// This code is distributed under the GNU Public License
//		which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************


#ifndef AVRLIBDEFS_H
#define AVRLIBDEFS_H

// Code compatibility to new AVR-libc
// outb(), inb(), BV(), sbi(), cbi(), sei(), cli()
#ifndef outb
	#define	outb(addr, data)	addr = (data)
#endif
#ifndef inb
	#define	inb(addr)			(addr)
#endif
#ifndef BV
	#define BV(bit)			(1<<(bit))
#endif
#ifndef cbi
	#define cbi(reg,bit)	reg &= ~(BV(bit))
#endif
#ifndef sbi
	#define sbi(reg,bit)	reg |= (BV(bit))
#endif
#ifndef cli
	#define cli()			__asm__ __volatile__ ("cli" ::)
#endif
#ifndef sei
	#define sei()			__asm__ __volatile__ ("sei" ::)
#endif
#ifndef bit_is_clr
	#define bit_is_clr(val) bit_is_clear(val)
#endif
/* Macros for access to 16-bit I/O registers (ADC, ICR1, OCR1, TCNT1) -
   read low byte first, then high byte (from the TEMP register),
   write the high byte first (to the TEMP register), then the low byte.
   If used from interrupts as well as from the main program, disable
   interrupts first, or use the *_atomic versions (avoid interrupts
   in the middle of operation - there is only one TEMP register).  */
   
#ifndef BV
  #define BV(x) (1 << (x))
#endif

#ifndef __SFR_OFFSET
#define __SFR_OFFSET 0
#endif /* !__SFR_OFFSET */

/* Memory mapped I/O - use for non-constant I/O space addresses.  */

#define __mmio(port) \
	(*((volatile uint8_t *)((port) - __SFR_OFFSET + 0x20)))

#define __mmio_word(port) \
	(*((volatile uint16_t *)((port) - __SFR_OFFSET + 0x20)))
   
   
#define __port_in_out_ok(port, size) \
  (__builtin_constant_p(port) && (port) <= 0x40 + __SFR_OFFSET - (size))

#define inp(port) \
  (__port_in_out_ok((port), 1) ? __inb((port)) : __mmio((port)))

#define outp(val,port) do {				\
	if (__port_in_out_ok((port), 1)) {		\
		if (__builtin_constant_p((val)) && ((val) == 0)) \
			__outb_zero((port));		\
		else					\
			__outb((val), (port));		\
	} else						\
		__mmio((port)) = (val);			\
 } while (0)



#define __inw(port) ({					\
	uint16_t __t;					\
	__asm__ __volatile__ (				\
		"in %A0,%1" "\n\t"			\
		"in %B0,(%1)+1"				\
		: "=r" (__t)				\
		: "M" ((uint8_t)((port)-__SFR_OFFSET))	\
	);						\
	__t;						\
 })

#define __inw_atomic(port) ({				\
	uint16_t __t;					\
	__asm__ __volatile__ (				\
		"in __tmp_reg__,__SREG__" "\n\t"	\
		"cli" "\n\t"				\
		"in %A0,%1" "\n\t"			\
		"out __SREG__,__tmp_reg__" "\n\t"	\
		"in %B0,(%1)+1"				\
		: "=r" (__t)				\
		: "M" ((uint8_t)((port)-__SFR_OFFSET))	\
		: "r0"					\
	);						\
	__t;						\
 })

#define __outw(val, port)				\
	__asm__ __volatile__ (				\
		"out (%1)+1,%B0" "\n\t"			\
		"out %1,%A0"				\
		: /* no outputs */			\
		: "r" ((uint16_t)(val)),		\
		  "M" ((uint8_t)((port)-__SFR_OFFSET))	\
	)

#define __outw_atomic(val, port)			\
	__asm__ __volatile__ (				\
		"in __tmp_reg__,__SREG__" "\n\t"	\
		"cli" "\n\t"				\
		"out (%1)+1,%B0" "\n\t"			\
		"out __SREG__,__tmp_reg__" "\n\t"	\
		"out %1,%A0"				\
		: /* no outputs */			\
		: "r" ((uint16_t)(val)),		\
		  "M" ((uint8_t)((port)-__SFR_OFFSET))	\
		: "r0"					\
	)

#define inw(port) \
  (__port_in_out_ok((port), 2) ? __inw(port) : __mmio_word(port))

#define outw(val, port) do {			\
	if (__port_in_out_ok((port), 2))	\
		__outw(val, port);		\
	else					\
		__mmio_word(port) = (val);	\
 } while (0)

// support for individual port pin naming in the mega128
// see port128.h for details
#ifdef __AVR_ATmega128__
// not currently necessary due to inclusion
// of these defines in newest AVR-GCC
// do a quick test to see if include is needed
#ifndef PD0
	#include "port128.h"
#endif
#endif

// use this for packed structures
// (this is seldom necessary on an 8-bit architecture like AVR,
//  but can assist in code portability to AVR)
#define GNUC_PACKED __attribute__((packed)) 

// port address helpers
#define DDR(x) ((x)-1)    // address of data direction register of port x
#define PIN(x) ((x)-2)    // address of input register of port x

// MIN/MAX/ABS macros
#define MIN(a,b)			((a<b)?(a):(b))
#define MAX(a,b)			((a>b)?(a):(b))
#define ABS(x)				((x>0)?(x):(-x))

// constants
#define PI		3.14159265359

#endif
